package typistcal.commandlogic;

import java.util.InputMismatchException;

import typistcal.userinterface.UserInterface;

//@author A0105620X
public class Keyword {
	protected static String input;

	protected static boolean containsKeyword(String keyword) {
		return input.toLowerCase().contains(keyword);
	}

	protected static boolean matchesKeyword(String keyword) {
		return input.equalsIgnoreCase(keyword);
	}

	protected static String remove(String keyword, String userInput) {
		return userInput.substring(userInput.indexOf(' ') + 1);
	}
	
	protected static int countOccurences(String keyword) {
		int count = 0;
		int index = 0;
		
		while ((index = input.indexOf(keyword, index)) != -1) {
			count++;
			index += keyword.length();
		}
		return count;
	}
}

class CommandTypeKeyword extends Keyword {	
	public static boolean isUndo(String userInput) {
		input = userInput;
		boolean isUndo = matchesKeyword("undo") || matchesKeyword("..");
		return isUndo;
	}

	public static boolean isRedo(String userInput) {
		input = userInput;
		boolean isRedo = matchesKeyword("redo") || matchesKeyword("..r");
		return isRedo;
	}

	private static int[] keywords = new int[5];
	private static final int ADD = 0;
	private static final int DEL = 1;
	private static final int SHOW = 2;
	private static final int UPDATE = 3;
	private static final int FIND = 4;

	private static int countKeywordFound() {
		return keywords[ADD] + keywords[DEL] + keywords[SHOW]
				+ keywords[UPDATE] + keywords[FIND];
	}

	public static CommandType findCommandTypeKeyword(String userInput) throws InputMismatchException {
		input = userInput.toLowerCase();
		CommandType keywordFound = findPriorityKeyword();

		if (keywordFound == null) {
			keywordFound = findNormalKeyword();
		}
		if(keywordFound==null||keywordFound==CommandType.INVALID){
			throw new InputMismatchException("No command type keyword found.");
		}
		return keywordFound;
	}

	private static CommandType findNormalKeyword() {
		updateKeywordCountNormal();
		int count = countKeywordFound();

		if (count == 0) {
			return null;
		} else if (count == 1) {
			return keywordDetermined();
		} else {
			if((keywords[ADD] == count)|| (keywords[DEL] ==count)||(keywords[SHOW] == count)
					||(keywords[UPDATE] ==count)||(keywords[FIND] ==count)){
				return keywordDetermined();
			}
			return userConfirmedKeyword();
		}
	}

	private static CommandType findPriorityKeyword() {

		updateKeywordCountPriority();
		int count = countKeywordFound();

		if (count == 0) {
			return null;
		} else if (count == 1) {
			return keywordDetermined();
		} else {
			if((keywords[ADD] == count)|| (keywords[DEL] ==count)||(keywords[SHOW] == count)
					||(keywords[UPDATE] ==count)||(keywords[FIND] ==count)){
				return keywordDetermined();
			}
			return userConfirmedKeyword();
		}
	}

	private static CommandType userConfirmedKeyword() {
		StringBuffer sb = constructMessageForKeywordConfirmation();
		
		String keywordConfirmed = UserInterface.displayAndAskForFeedback(sb.toString());
		
		boolean isConfirmed = false;
		CommandType thisCommandType=null;
		while(!isConfirmed){
			try{
				thisCommandType = findCommandTypeKeyword(keywordConfirmed);
				isConfirmed = true;
			}catch(InputMismatchException e){
				keywordConfirmed = UserInterface.displayAndAskForFeedback(e.getMessage()+"\n\nPlease enter your keyword again");
			}
		}
		return thisCommandType;
	}

	private static StringBuffer constructMessageForKeywordConfirmation() {
		StringBuffer sb = new StringBuffer(
				"Do you want to");
		if(keywords[ADD] > 0){
			sb.append(" add,");
		}
		if(keywords[DEL] > 0){
			sb.append(" delete,");
		}
		if(keywords[SHOW] > 0){
			sb.append(" show,");
		}
		if(keywords[UPDATE] > 0){
			sb.append(" update,");
		}
		if(keywords[FIND] > 0){
			sb.append(" find,");
		}
		
		sb.replace(sb.lastIndexOf(","), sb.lastIndexOf(",")+1, "?");
		
		if(sb.indexOf(",")==sb.lastIndexOf(",")){
			sb.replace(sb.indexOf(","),sb.indexOf(",")+1," or");
		}else{
			sb.replace(sb.lastIndexOf(","), sb.lastIndexOf(",")+1, " or");
		}
		
		sb.append("\n\nTips: keywords such as \"..a\" can help you specify the command");
		return sb;
	}

	private static void updateKeywordCountPriority() {
		keywords[ADD] = countOccurences("..a");
		keywords[DEL] = countOccurences("..d");
		keywords[SHOW] = countOccurences("..s");
		keywords[UPDATE] = countOccurences("..u");
		keywords[FIND] = countOccurences("..f");
	}

	private static void updateKeywordCountNormal() {
		keywords[ADD] = countOccurences("add");
		keywords[DEL] = countOccurences("delete")+ countOccurences("del");
		keywords[SHOW] = countOccurences("show");
		keywords[UPDATE] = countOccurences("update")+ countOccurences("upd");
		keywords[FIND] = countOccurences("find");
	}

	private static CommandType keywordDetermined() {
		if (keywords[ADD] >= 1) {
			return CommandType.ADD_INFO;
		} else if (keywords[DEL] >= 1) {
			return CommandType.DELETE_INFO;
		} else if (keywords[SHOW] >= 1) {
			return CommandType.SHOW_INFO;
		} else if (keywords[UPDATE] >= 1) {
			return CommandType.UPDATE_INFO;
		} else if (keywords[FIND] >= 1) {
			return CommandType.FIND_INFO;
		} 
		return CommandType.INVALID;
	}

	public static String remove(CommandType keyword, String userInput) {
		input = userInput;
		if (removePriorityKeyword(keyword)) {
			return input;
		} else {
			removeNormalKeyword(keyword);
			return input;
		}
	}

	private static void removeNormalKeyword(CommandType keyword) {
		String target = castCommandTypeToNormal(keyword);
		input = input.replaceFirst(target, "");
	}

	private static boolean removePriorityKeyword(CommandType keyword) {
		String target = castCommandTypeToPriority(keyword);
		String inputCopy = input;
		input = input.replaceFirst(target, "");
		
		return !inputCopy.equals(input);
	}

	private static String castCommandTypeToPriority(CommandType keyword) {
		switch (keyword) {
		case ADD_INFO:
			return "[.]{2}(?i)a";
		case DELETE_INFO:
			return "[.]{2}(?i)d";
		case UPDATE_INFO:
			return "[.]{2}(?i)u";
		case SHOW_INFO:
			return "[.]{2}(?i)s";
		case FIND_INFO:
			return "[.]{2}(?i)f";
		default:
			return null;
		}
	}

	private static String castCommandTypeToNormal(CommandType keyword) {
		switch (keyword) {
		case ADD_INFO:
			return "(?i)add";
		case DELETE_INFO:
			return "(?i)delete|(?i)del";
		case UPDATE_INFO:
			return "(?i)update|(?i)upd";
		case SHOW_INFO:
			return "(?i)show";
		case FIND_INFO:
			return "(?i)find";
		default:
			return null;
		}
	}
}

class EventKeyword extends Keyword {
	public static boolean isComplete(String input){
		return input.equalsIgnoreCase("complete")||input.equalsIgnoreCase("completed")||input.equalsIgnoreCase("done")||input.equalsIgnoreCase("finished");
	}
	
	public static boolean isIncomplete(String input){
		return input.equalsIgnoreCase("incomplete")||input.equalsIgnoreCase("unfinished");
	}
}
